import {SQLiteDataType} from "../../types";

/**
 * 类型校验和转换工具类
 */
export class TypeValidationUtil {
  /**
   * 验证值是否符合指定的SQLite类型
   * @param value 要验证的值
   * @param expectedType 期望的SQLite类型
   * @returns 验证是否通过
   */
  static isValidType(value: any, expectedType: SQLiteDataType): boolean {
    if (value === null || value === undefined) {
      return true; // SQLite允许任何列存储NULL值
    }

    switch (expectedType) {
      case 'INTEGER':
        return Number.isInteger(value);
      case 'REAL':
        return typeof value === 'number';
      case 'TEXT':
        return typeof value === 'string' || value instanceof Date || this.canBeConvertedToString(value);
      case 'BLOB':
        return value instanceof Buffer || value instanceof Uint8Array || value instanceof ArrayBuffer;
      case 'BOOLEAN':
        return typeof value === 'boolean' || value === 0 || value === 1;
      case 'DATE':
      case 'DATETIME':
        return value instanceof Date || (typeof value === 'string' && !isNaN(Date.parse(value)));
      case 'NUMERIC':
        return typeof value === 'number' || (typeof value === 'string' && !isNaN(Number(value)));
      default:
        return true; // 未知类型，默认通过
    }
  }

  /**
   * 将值转换为指定的SQLite类型
   * @param value 要转换的值
   * @param targetType 目标SQLite类型
   * @returns 转换后的值
   */
  static convertToType(value: any, targetType: SQLiteDataType): any {
    if (value === null || value === undefined) {
      return null;
    }

    try {
      switch (targetType) {
        case 'INTEGER':
          return this.toInteger(value);
        case 'REAL':
          return this.toReal(value);
        case 'TEXT':
          return this.toText(value);
        case 'BLOB':
          return this.toBlob(value);
        case 'BOOLEAN':
          return this.toBoolean(value);
        case 'DATE':
        case 'DATETIME':
          return this.toDate(value);
        case 'NUMERIC':
          return this.toNumeric(value);
        default:
          return value;
      }
    } catch (error: any) {
      throw new Error(`无法将值 "${value}" 转换为 ${targetType} 类型: ${error.message}`);
    }
  }

  /**
   * 检查值并执行类型校验或转换
   * @param value 要处理的值
   * @param columnType 列的SQLite类型
   * @param strictTypeCheck 是否启用严格类型检查
   * @returns 处理后的值
   */
  static validateOrConvertValue(value: any, columnType: SQLiteDataType, strictTypeCheck: boolean): any {
    if (value === null || value === undefined) {
      return null;
    }

    // 如果启用了严格类型检查且类型不匹配
    if (strictTypeCheck && !this.isValidType(value, columnType)) {
      throw new Error(`类型校验失败: 值 "${value}" (${typeof value}) 与期望的类型 ${columnType} 不匹配`);
    }

    // 如果未启用严格类型检查或类型匹配，尝试转换
    return this.convertToType(value, columnType);
  }

  /**
   * 检查值是否可以转换为字符串
   * @param value 要检查的值
   * @returns 是否可以转换为字符串
   */
  private static canBeConvertedToString(value: any): boolean {
    try {
      return typeof value.toString === 'function';
    } catch {
      return false;
    }
  }

  /**
   * 转换为整数
   * @param value 要转换的值
   * @returns 转换后的整数
   */
  private static toInteger(value: any): number {
    if (typeof value === 'number') {
      return Math.floor(value);
    }
    if (typeof value === 'boolean') {
      return value ? 1 : 0;
    }
    if (value instanceof Date) {
      return Math.floor(value.getTime() / 1000);
    }
    const parsed = parseInt(String(value), 10);
    if (isNaN(parsed)) {
      throw new Error(`无法将 "${value}" 转换为整数`);
    }
    return parsed;
  }

  /**
   * 转换为浮点数
   * @param value 要转换的值
   * @returns 转换后的浮点数
   */
  private static toReal(value: any): number {
    if (typeof value === 'number') {
      return value;
    }
    if (typeof value === 'boolean') {
      return value ? 1 : 0;
    }
    if (value instanceof Date) {
      return value.getTime() / 1000;
    }
    const parsed = parseFloat(String(value));
    if (isNaN(parsed)) {
      throw new Error(`无法将 "${value}" 转换为浮点数`);
    }
    return parsed;
  }

  /**
   * 转换为文本
   * @param value 要转换的值
   * @returns 转换后的文本
   */
  private static toText(value: any): string {
    if (typeof value === 'string') {
      return value;
    }
    if (value instanceof Date) {
      return value.toISOString();
    }
    if (typeof value === 'object' && value !== null) {
      try {
        return JSON.stringify(value);
      } catch {
        return String(value);
      }
    }
    return String(value);
  }

  /**
   * 转换为BLOB
   * @param value 要转换的值
   * @returns 转换后的BLOB
   */
  private static toBlob(value: any): Buffer {
    if (value instanceof Buffer) {
      return value;
    }
    if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
      return Buffer.from(value);
    }
    if (typeof value === 'string') {
      return Buffer.from(value);
    }
    try {
      return Buffer.from(JSON.stringify(value));
    } catch {
      throw new Error(`无法将 "${value}" 转换为BLOB`);
    }
  }

  /**
   * 转换为布尔值
   * @param value 要转换的值
   * @returns 转换后的布尔值
   */
  private static toBoolean(value: any): number {
    if (typeof value === 'boolean') {
      return value ? 1 : 0;
    }
    if (value === 0 || value === '0' || value === 'false' || value === 'False' || value === 'FALSE' || value === '') {
      return 0;
    }
    return 1;
  }

  /**
   * 转换为日期
   * @param value 要转换的值
   * @returns 转换后的日期ISO字符串
   */
  private static toDate(value: any): string {
    if (value instanceof Date) {
      return value.toISOString();
    }
    if (typeof value === 'number') {
      return new Date(value).toISOString();
    }
    if (typeof value === 'string') {
      const date = new Date(value);
      if (isNaN(date.getTime())) {
        throw new Error(`无效的日期字符串: "${value}"`);
      }
      return date.toISOString();
    }
    throw new Error(`无法将 "${value}" 转换为日期`);
  }

  /**
   * 转换为数值类型
   * @param value 要转换的值
   * @returns 转换后的数值
   */
  private static toNumeric(value: any): number | string {
    if (typeof value === 'number') {
      return value;
    }
    if (typeof value === 'boolean') {
      return value ? 1 : 0;
    }
    if (typeof value === 'string') {
      const trimmed = value.trim();
      if (trimmed === '') {
        return 0;
      }
      if (!isNaN(Number(trimmed))) {
        return Number(trimmed);
      }
      return trimmed;
    }
    if (value instanceof Date) {
      return value.getTime();
    }
    throw new Error(`无法将 "${value}" 转换为数值类型`);
  }
}
